#ifndef HTTPCONNECTION_H
#define HTTPCONNECTION_H
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <map>

#include "../lock/locker.h"
#include "../CGImysql/sql_connection_pool.h"
#include "../timer/lst_timer.h"
#include "../log/log.h"

class http_conn
{
public:
    static const int FILENAME_LEN = 200;			//设置要读取文件的名称的大小
    static const int READ_BUFFER_SIZE = 2048;			//设置读缓冲区 m_read_buf 的大小
    static const int WRITE_BUFFER_SIZE = 1024;		//设置写缓冲区 m_write_buf 的大小
    enum METHOD						//报文的请求方法，本项目只用到GET和POST
    {
        GET = 0,
        POST,
        HEAD,
        PUT,
        DELETE,
        TRACE,
        OPTIONS,
        CONNECT,
        PATH
    };
    enum CHECK_STATE						//主状态机的状态
    {
        CHECK_STATE_REQUESTLINE = 0,				//解析请求行
        CHECK_STATE_HEADER,					//解析请求头
        CHECK_STATE_CONTENT					//解析消息体，仅用于解析POST请求
    };
    enum HTTP_CODE						//报文解析的结果		服务器接收到报文后对其解析的结果
    {
        NO_REQUEST,						//请求不完整，需要继续读取请求报文数据
        GET_REQUEST,						//获得了完整的HTTP请求
        BAD_REQUEST,						//HTTP请求报文有语法错误
        NO_RESOURCE,						
        FORBIDDEN_REQUEST,
        FILE_REQUEST,
        INTERNAL_ERROR,					//服务器内部错误
        CLOSED_CONNECTION
    };
    enum LINE_STATUS						//从状态机的状态
    {
        LINE_OK = 0,						//完整读取一行
        LINE_BAD,						//报文语法有误
        LINE_OPEN						//读取的行不完整
    };

public:
    http_conn() {}
    ~http_conn() {}

public:
    void init(int sockfd, const sockaddr_in &addr, char *, int, int, string user, string passwd, string sqlname);		//初始化套接字地址，函数内部会调用私有方法 init()
    void close_conn(bool real_close = true);					//关闭HTTP连接
    void process();								//
    bool read_once();								//读取浏览器端发来的全部数据
    bool write();								//响应报文写入函数
    sockaddr_in *get_address()
    {
        return &m_address;
    }
    void initmysql_result(connection_pool *connPool);			//同步线程初始化数据库读取表
    int timer_flag;
    int improv;


private:
    void init();
    HTTP_CODE process_read();							//从读缓冲区 m_read_buf 读取，并处理请求报文
    bool process_write(HTTP_CODE ret);					//向写缓冲区 m_write_buf 写入响应报文数据
    HTTP_CODE parse_request_line(char *text);					//主状态机解析 报文中的请求行数据
    HTTP_CODE parse_headers(char *text);					//主状态机解析 报文中的请求头数据
    HTTP_CODE parse_content(char *text);					//主状态机解析 报文中的请求内容
    HTTP_CODE do_request();							//生成响应报文
    char *get_line() { return m_read_buf + m_start_line; };			//m_start_line 是每一行数据在 m_read_buf 中的起始位置 		get_line用于将指针向后偏移，指向未处理的字符
    
    LINE_STATUS parse_line();							//从状态机读取一行，分析是请求报文的哪一部分
    void unmap();
    
    bool add_response(const char *format, ...);				//根据响应报文的格式，生成对应的8个部分，以下函数均由do_request调用
    bool add_content(const char *content);
    bool add_status_line(int status, const char *title);
    bool add_headers(int content_length);
    bool add_content_type();
    bool add_content_length(int content_length);
    bool add_linger();
    bool add_blank_line();							//添加空行

public:
    static int m_epollfd;
    static int m_user_count;
    MYSQL *mysql;
    int m_state;  //读为0, 写为1

private:
    int m_sockfd;
    sockaddr_in m_address;
    
    char m_read_buf[READ_BUFFER_SIZE];					//存储读取的请求报文数据
    int m_read_idx;								//读缓冲区 m_read_buf 中数据的最后一个字节的下一个位置
    int m_checked_idx;								//当前读取的位置
    int m_start_line;								//每一行数据在 m_read_buf 中的起始位置 
    
    char m_write_buf[WRITE_BUFFER_SIZE];					//存储发出的响应报文数据
    int m_write_idx;								//指示 buffer中的长度
    
    CHECK_STATE m_check_state;						//主状态机的状态
    METHOD m_method;								//请求的方法
    
    //以下为解析请求报文中对应的6个变量
    char m_real_file[FILENAME_LEN];						//存储读取文件的名称
    char *m_url;
    char *m_version;
    char *m_host;
    int m_content_length;
    bool m_linger;
    
    char *m_file_address;							//读取服务器上的文件地址
    struct stat m_file_stat;
    struct iovec m_iv[2];							//i/o 向量机制 iovec			m_iv[0]：为存储报文状态行的缓冲区、m_iv[1]：指向资源文件的指针（一个mmap映射）
    int m_iv_count;
    int cgi;        								//是否启用的POST
    char *m_string; 								//存储请求头数据
    int bytes_to_send;								//剩余待发送的字节数
    int bytes_have_send;							//已经发送的字节数
    char *doc_root;

    map<string, string> m_users;
    int m_TRIGMode;
    int m_close_log;

    char sql_user[100];
    char sql_passwd[100];
    char sql_name[100];
};

#endif
